package com.tangula.bleserver

import android.Manifest
import android.annotation.TargetApi
import android.app.Activity
import android.bluetooth.*
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import kotlinx.android.synthetic.main.activity_main.*
import android.bluetooth.le.AdvertiseCallback
import android.bluetooth.le.AdvertiseData
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager.PERMISSION_GRANTED
import android.os.ParcelUuid
import android.util.Log
import android.view.View
import android.widget.Toast
import java.util.*
import android.bluetooth.le.AdvertiseSettings


class BleServer{
    var z = "0"
    var yyy = "009"
    //hdmi
    var x = "1"
    //auto switch
    var w = "0" // 1 on; 0 off
    //cec
    var v = "0" // 1 on; 0 off
    //ir
    var u = "0" // 1 on; 0 off
    //learn
    var t = "0" // 1 on; 0 off

    fun changeHdmi(cmd:String):String{
        when(cmd){
            "S1"->{
                x="1"
            }
            "S2"->{
                x="2"
            }
            "S3"->{
                x="3"
            }
            "S4"->{
                x="4"
            }
        }
        return "${cmd}A"
    }

    fun changeSwitch(cmd:String):String{
        when(cmd){
            "ASW1"->{
                w="1"
            }
            "ASW0"->{
                w="0"
            }
        }
        return "${cmd}A"
    }

    fun changeCec(cmd:String):String{
        when(cmd){
            "CE1"->{
                v="1"
            }
            "CE0"->{
                v="0"
            }
        }
        return "${cmd}A"
    }

    fun changeIr(cmd:String):String{
        when(cmd){
            "IR1"->{
                u="1"
            }
            "IR0"->{
                u="0"
            }
        }
        return "${cmd}A"
    }

    fun execCmd(cmd:String):String{
        if(cmd.startsWith("L")){
            t="1"
            Thread{
                try {
                    Thread.sleep(5000)
                }catch (e:Exception){
                    Log.e(MainActivity.LOG_TAG, e.localizedMessage,e)
                }
                t="0"
            }.start()
        }
        return ""
    }

    fun exeGM(cmd:String):String{
        return "GMA"
    }

    fun exeDN(cmd:String):String{
        return "DNA"
    }

}


class MainActivity : AppCompatActivity() {
    companion object {
        val LOG_TAG = "console"
    }

    val REQUEST_CODE_OPEN_BT = 0x1000
    val REQUEST_CODE_REQUEST_BT_PERMS = 0x1001

    val STR_SERVICE_UUID = "D973F2E0-B19E-11E2-9E96-0800200C9A66"
    val STR_CHAR_IN_UUID = "D973F2E2-B19E-11E2-9E96-0800200C9A66"
    val STR_CHAR_OUT_UUID = "D973F2E1-B19E-11E2-9E96-0800200C9A66"

    val UUID_SERVICE = UUID.fromString(STR_SERVICE_UUID)
    val UUID_CLIENT_WRITE = UUID.fromString(STR_CHAR_IN_UUID)
    val UUID_CLIENT_RECEIVE_NOTICICATION = UUID.fromString(STR_CHAR_OUT_UUID)


    val server=BleServer()

    lateinit var bluetoothManager:BluetoothManager
    lateinit var btAdapter:BluetoothAdapter

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        if (isSupportBle(this)) {

            vw_not_support_ble.visibility = View.GONE




            vw_on.setOnCheckedChangeListener{ _, value ->
                if(value){
                    if(
                            this.checkSelfPermission(Manifest.permission.BLUETOOTH)!=PERMISSION_GRANTED
                        ||this.checkSelfPermission(Manifest.permission.BLUETOOTH_ADMIN)!=PERMISSION_GRANTED
                        ||this.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION)!= PERMISSION_GRANTED
                        ||this.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION)!= PERMISSION_GRANTED
                    ){
                        Log.v(LOG_TAG, "request permissions")
                        this.requestPermissions(
                                arrayOf(
                                        Manifest.permission.BLUETOOTH,
                                        Manifest.permission.BLUETOOTH_ADMIN,
                                        Manifest.permission.ACCESS_COARSE_LOCATION,
                                        Manifest.permission.ACCESS_FINE_LOCATION
                                        ),
                                REQUEST_CODE_REQUEST_BT_PERMS)
                    }else{
                        startBleServer()
                    }
                }else{
                    stopBleServer()
                }

            }

            if(isBleEnable(this)){
                vw_on.visibility = View.VISIBLE
                vw_ble_not_open.visibility = View.GONE
                bluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
                btAdapter = BluetoothAdapter.getDefaultAdapter()
                vw_on.isChecked = true
            }else{
                vw_on.visibility = View.GONE
                vw_ble_not_open.visibility = View.VISIBLE
            }


        } else {
            vw_on.visibility = View.GONE
            vw_not_support_ble.visibility = View.VISIBLE
            vw_ble_not_open.visibility = View.GONE
        }

    }

    fun onClick(vw:View){
        if(vw.id==vw_ble_not_open.id){
            enableBle(this, REQUEST_CODE_OPEN_BT)
        }
    }

    @TargetApi(18)
    fun isSupportBle(context: Context): Boolean {
        return if (context.packageManager.hasSystemFeature("android.hardware.bluetooth_le")) {
            val manager = context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
            manager.adapter != null
        } else {
            false
        }
    }

    @TargetApi(18)
    fun isBleEnable(context: Context): Boolean {
        if(!isSupportBle(context)) {
            return false;
        } else {
            val manager = context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
            return manager.getAdapter().isEnabled();
        }
    }

    //开启蓝牙
    fun enableBle(act: Activity, requestCode:Int) {
        val mIntent = Intent("android.bluetooth.adapter.action.REQUEST_ENABLE")
        act.startActivityForResult(mIntent, requestCode)
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        if(requestCode == REQUEST_CODE_OPEN_BT){
            recreate()
        }else{
            super.onActivityResult(requestCode, resultCode, data)
        }
    }

    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        if(requestCode == REQUEST_CODE_REQUEST_BT_PERMS){
            var allpass= true
            val it = grantResults.iterator()
            while(it.hasNext()){
                allpass = it.nextInt()== PERMISSION_GRANTED
                if(!allpass){
                    break
                }
            }
            if(allpass){
                startBleServer()
            }else{
                Toast.makeText(this, "Please grant bluetooth and location permissions to the app.", Toast.LENGTH_LONG).show()
                recreate()
            }
        }
    }

    var bleServer:BluetoothGattServer?=null


    private fun startBleServer(){
        Log.v(LOG_TAG, "start ble service")
        val advertiseData = AdvertiseData.Builder().addServiceUuid(ParcelUuid(UUID_SERVICE)).setIncludeDeviceName(true).build()
        val settings = AdvertiseSettings.Builder().setConnectable(true).build()
        btAdapter.bluetoothLeAdvertiser.startAdvertising(settings, advertiseData, object:AdvertiseCallback(){
            override fun onStartSuccess(settingsInEffect: AdvertiseSettings?) {
                super.onStartSuccess(settingsInEffect)
                Log.v(LOG_TAG, "start ble advertise successfully")

                bleServer = bluetoothManager.openGattServer(this@MainActivity, object: BluetoothGattServerCallback(){
                    //BLE 服务端的各种监听
                    override fun onServiceAdded(status: Int, service: BluetoothGattService?) {
                        super.onServiceAdded(status, service)
                        Log.v(LOG_TAG, "add service "+service?.uuid)
                    }

                    override fun onConnectionStateChange(device: BluetoothDevice?, status: Int, newState: Int) {
                        super.onConnectionStateChange(device, status, newState)
                        Log.v(LOG_TAG, "连接状态改变，设备：[${device?.name}:${device?.address}] 状态:${status} 新状态:${newState}")
                    }

                    override fun onCharacteristicWriteRequest(device: BluetoothDevice?,
                                                              requestId: Int,
                                                              characteristic: BluetoothGattCharacteristic?,
                                                              preparedWrite: Boolean,
                                                              responseNeeded: Boolean,
                                                              offset: Int,
                                                              value: ByteArray?) {
                        super.onCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite, responseNeeded, offset, value)

                        Log.v(LOG_TAG,"on write request: ${device?.address}, ${requestId}," +
                                " ${characteristic?.uuid}, preparedWrite:${preparedWrite}," +
                                " resp needed:${responseNeeded}, offset:${offset}, value:${String(value!!)}")

                        bleServer?.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, 0, value)

                        value?.also {
                            val cmd = String(value)
                            handlerCommand(device!!, cmd)
                        }


                    }

                    override fun onExecuteWrite(device: BluetoothDevice?, requestId: Int, execute: Boolean) {
                        super.onExecuteWrite(device, requestId, execute)
                        Log.v(LOG_TAG,"on execute write. ${device?.address}, $requestId, $execute")
                    }

                    override fun onNotificationSent(device: BluetoothDevice?, status: Int) {
                        super.onNotificationSent(device, status)
                        Log.v(LOG_TAG, "notification sent device:${device?.address}")
                    }


                })

                bleServer?.addService(buildService())

            }

            override fun onStartFailure(errorCode: Int) {
                super.onStartFailure(errorCode)
                val msg = "start ble advertise failure, return error \"${errorCode}\"."
                Toast.makeText(this@MainActivity, msg, Toast.LENGTH_LONG).show()
                Log.w(LOG_TAG, msg)
            }

        })

    }

    private fun handlerCommand(device:BluetoothDevice, command:String){
        var resp = "";
        when(command){
            "S1","S2","S3", "S4"->{
                resp = server.changeHdmi(command)
            }
            "ASW0","ASW1"->{
                resp = server.changeSwitch(command)
            }
            "CE0","CE1"->{
                resp = server.changeCec(command)
            }
            "IR0","IR1"->{
                resp = server.changeIr(command)
            }

            else->{
                when{
                    command.startsWith("GM")->{
                        resp=server.exeGM(command)
                    }
                    command.startsWith("DN")->{
                        resp=server.exeDN(command)
                    }
                    command.startsWith("STAT")->{
                        resp = "STAT${server.z}${server.yyy}${server.x}${server.w}${server.v}${server.u}${server.t}"
                    }else->{
                        resp = server.execCmd(command)
                    }
                }
            }
        }
        if(!resp.isBlank()) {
            charNotify?.setValue(resp)
            Log.v(LOG_TAG, "notify: $resp")
            bleServer?.notifyCharacteristicChanged(device, charNotify, false)
        }
    }

    var charNotify:BluetoothGattCharacteristic? = null

    private fun buildService(): BluetoothGattService {
        val res = BluetoothGattService(UUID_SERVICE, BluetoothGattService.SERVICE_TYPE_PRIMARY)

        val notify_char = BluetoothGattCharacteristic(UUID_CLIENT_RECEIVE_NOTICICATION,
                BluetoothGattCharacteristic.PROPERTY_NOTIFY,
                BluetoothGattCharacteristic.PERMISSION_READ
        )

        charNotify = notify_char

        val write_char = BluetoothGattCharacteristic(UUID_CLIENT_WRITE,
                BluetoothGattCharacteristic.PROPERTY_WRITE
                        or BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE,
                    BluetoothGattCharacteristic.PERMISSION_WRITE
                )

        res.addCharacteristic(notify_char)
        res.addCharacteristic(write_char)

        return res
    }


    private fun stopBleServer(){
        Log.v(LOG_TAG, "stop ble service")
        btAdapter.bluetoothLeAdvertiser.stopAdvertising(object:AdvertiseCallback(){
            override fun onStartSuccess(settingsInEffect: AdvertiseSettings?) {
                super.onStartSuccess(settingsInEffect)
                Log.v(LOG_TAG, "stop ble advertise successfully")
            }

            override fun onStartFailure(errorCode: Int) {
                super.onStartFailure(errorCode)
                val msg = "stop ble advertise failure, return error \"${errorCode}\"."
                Toast.makeText(this@MainActivity, msg, Toast.LENGTH_LONG).show()
                Log.w(LOG_TAG, msg)
            }
        })

    }
}
